using System.Collections;
using System.Collections.Specialized;
using System.ComponentModel;

namespace TheSalLab.MauiBehaviors;

public class MauiBindableObjectCollection : BindableObject,
    IEnumerable<BindableObject>, INotifyPropertyChanged {
    private readonly List<BindableObject> _items = new();

    public event NotifyCollectionChangedEventHandler CollectionChanged;

    public int IndexOf(BindableObject item) => _items.IndexOf(item);

    public void Insert(int index, BindableObject item) {
        _items.Insert(index, item);
        CollectionChanged(this,
            new NotifyCollectionChangedEventArgs(
                NotifyCollectionChangedAction.Add, item, index));
    }

    public void RemoveAt(int index) {
        var oldItem = _items[index];
        _items.RemoveAt(index);
        CollectionChanged(this,
            new NotifyCollectionChangedEventArgs(
                NotifyCollectionChangedAction.Remove, oldItem, index));
    }

    public BindableObject this[int index] {
        get => _items[index];
        set {
            var oldItem = _items[index];
            _items[index] = value;
            CollectionChanged(this,
                new NotifyCollectionChangedEventArgs(
                    NotifyCollectionChangedAction.Replace, value, oldItem));
        }
    }

    public void Add(BindableObject item) {
        _items.Add(item);
        CollectionChanged(this,
            new NotifyCollectionChangedEventArgs(
                NotifyCollectionChangedAction.Add, item, _items.Count - 1));
    }

    public void Clean() {
        _items.Clear();
        CollectionChanged(this,
            new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction
                .Reset));
    }

    public bool Contains(BindableObject item) => _items.Contains(item);

    public void CopyTo(BindableObject[] array, int arrayIndex) =>
        _items.CopyTo(array, arrayIndex);

    public bool Remove(BindableObject item) {
        var oldIndex = IndexOf(item);

        if (!_items.Remove(item)) {
            return false;
        }

        CollectionChanged(this,
            new NotifyCollectionChangedEventArgs(
                NotifyCollectionChangedAction.Remove, item, oldIndex));
        return true;
    }

    public int Count => _items.Count;

    public bool IsReadOnly => false;

    IEnumerator IEnumerable.GetEnumerator() {
        return GetEnumerator();
    }

    public IEnumerator<BindableObject> GetEnumerator() =>
        _items.GetEnumerator();
}